package com.springmvc.servlet;

import com.bruce.exception.ContextException;
import com.springmvc.anotation.Controller;
import com.springmvc.anotation.RequestMapping;
import com.springmvc.anotation.RequestParam;
import com.springmvc.context.WebApplicationContext;
import com.springmvc.handler.MyHandler;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DispatcherServlet extends HttpServlet {

    private WebApplicationContext webApplicationContext;

    // 存储url和对象的映射关系
    List<MyHandler> handlerList = new ArrayList<>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        // servlet初始化时
        String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
        // 创建spring容器
        webApplicationContext = new WebApplicationContext(contextConfigLocation);
        // 初始化spring容器
        webApplicationContext.refresh();
        // 初始化请求映射
        initHandleMapping();
        System.out.println(handlerList);
    }

    //初始化请求映射
    private void initHandleMapping() {
        // 判断iocmap中是否有bean对象
        if (webApplicationContext.iocMap.isEmpty()){
            throw new ContextException("Spring容器为空");
        }
        for (Map.Entry<String ,Object> entry:webApplicationContext.iocMap.entrySet()){
            Class<?> clazz = entry.getValue().getClass();
            if (clazz.isAnnotationPresent(Controller.class)){
                Method[] declaredMethods = clazz.getDeclaredMethods();
                for (Method declaredMethod : declaredMethods) {
                    if (declaredMethod.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping requestMapping = declaredMethod.getAnnotation(RequestMapping.class);
                        // /user/query
                        String url = requestMapping.value();
                        MyHandler handler = new MyHandler(url, entry.getKey(), declaredMethod);
                        handlerList.add(handler);
                    }
                }
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 请求的分发  处理
        excuteDispatch(req,resp);
    }

    private void excuteDispatch(HttpServletRequest req, HttpServletResponse resp) {
        MyHandler handler = getHandler(req);
        try {
            if (handler==null){
                resp.getWriter().print("<h1>404</h1>");
            }
            Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();
            // 定义一个参数的数组
            Object[] params = new Object[parameterTypes.length];

            for (int i = 0; i < parameterTypes.length; i++) {
                Class<?> parameterType = parameterTypes[i];
                if ("HttpServletRequest".equals(parameterType.getSimpleName())){
                    params[i]=req;
                }else if ("HttpServletResponse".equals(parameterType.getSimpleName())){
                   params[i]=resp;
                }
            }

            // 获取请求中的参数集合
            Map<String ,String[]> parameterMap = req.getParameterMap();

            for (Map.Entry<String ,String[]> entry:parameterMap.entrySet()){
                String name = entry.getKey();
                String value = entry.getValue()[0];
                System.out.println("请求参数"+name+"===="+value);
                int i = hasRequestParam(handler.getMethod(), name);
                if (i!=-1){
                    params[i]=value;
                }else {
                    List<String> names = getparameterName(handler.getMethod());
                    System.out.println(names);
                    for (String s : names) {
                        if (name.equals(s)){
                            for (int j = 0; j < names.size(); j++) {
                                if (name.equals(names.get(i))){
                                    params[i]=value;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            // 调用控制中的方法
            handler.getMethod().invoke(handler.getController(),params);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取请求对应的handler
    public MyHandler getHandler(HttpServletRequest request){
        // user/query
        String requestURI = request.getRequestURI();
        for (MyHandler myHandler : handlerList) {
            if (myHandler.getUrl().equals(requestURI)){
                return myHandler;
            }
        }
        return null;
    }

    // 判断控制器方法的参数 是否有requestParam注解 找到对应值并返回参数
    public int hasRequestParam(Method method,String name){
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter p = parameters[i];
            boolean b = p.isAnnotationPresent(RequestParam.class);
            if (b){
                RequestParam requestParam = p.getAnnotation(RequestParam.class);
                String requestParamValue = requestParam.value();
                if (name.equals(requestParamValue)){
                    return i;
                }
            }
        }
        return -1;
    }

    // 获取控制器方法参数的名字
    public  List<String > getparameterName(Method method){
        List<String> list = new ArrayList<String>();
        Parameter[] parameters = method.getParameters();
        for (Parameter parameter : parameters) {
            list.add(parameter.getName());
        }
        return null;
    }
}
